home *** CD-ROM | disk | FTP | other *** search
/ Fritz: All Fritz / All Fritz.zip / All Fritz / FILES / DEMO_VGA / FRSTM1.LZH / GIFSAVE.C < prev    next >
C/C++ Source or Header  |  1989-03-26  |  8KB  |  260 lines

  1. #include <string.h>
  2. #include <stdio.h>
  3. #include <graph.h>
  4. #include <conio.h>
  5. #include <stdlib.h>
  6. #include "chkpoint.h"
  7. #include "xbit.h"
  8.  
  9. /* This is code I shamelessly swiped from Bert Tyler's FRACSRC.ARC with
  10.    some very minor modifications.
  11.                                  -Mark */
  12.  
  13. /*
  14.          Save-To-Disk Routines (GIF)
  15.  
  16. The following routines perform the GIF encoding when the 's' key is pressed.
  17. The routines refer to several variables that are declared elsewhere
  18. [colors, xdots, ydots, and 'dacbox'], and rely on external routines to
  19. actually read and write screen pixels [getcolor(x,y) and putcolor(x,y,color)].
  20. (Writing pixels is just stuffed in here as a sort of on-line status report.)
  21. Otherwise, they perform a generic GIF-encoder function.
  22.  
  23. Note that these routines use small string- and hash-tables, and "flush"
  24. the GIF entries whenever the hash-table gets two-thirds full or the string
  25. table gets full.   They also use the GIF encoding technique of limiting the
  26. encoded string length to a specific size, "adding" a string to the hash table
  27. at that point even if a matching string exists ("adding" is in quotes, because
  28. if a matching string exists we can increment the code counter but safely throw
  29. the duplicate string away, saving both string space and a hash table entry).
  30.  
  31.    This results in relatively good speed and small data space, but at the
  32. expense of compression efficiency (filesize).   These trade-offs could be
  33. adjusted by modifying the #DEFINEd variables below.
  34.  
  35. */
  36.  
  37. #define MAXTEST   200
  38. #define MAXENTRY  3001     /* a prime number is best, here */
  39. #define MAXSTRING 40000
  40.  
  41. char numsaves = 0;    /* For adjusting 'save-to-disk' filenames */
  42.  
  43. FILE *out;
  44.  
  45. unsigned lentest, lastentry, numentries, numrealentries, nextentry;
  46. int clearcode, endcode;
  47. int strlocn[MAXENTRY], entrynum[MAXENTRY];
  48. unsigned char teststring[MAXTEST], codedstrings[MAXSTRING];
  49. unsigned int hashcode;
  50.  
  51. unsigned char blockcount, block[266];
  52. int startbits, codebits, bytecount, bitcount;
  53.  
  54. void raster(int code)            /* routine to block and output codes */
  55. {
  56. unsigned int icode, i, j;
  57.  
  58. if (code == 9999) {        /* special start-up signal */
  59.    bytecount = 0;
  60.    bitcount = 0;
  61.    for (i = 0; i < 266; i++)
  62.       block[i] = 0;
  63.    return;
  64.    }
  65.  
  66. icode = code << bitcount;     /* update the bit string */
  67. block[bytecount  ] |= (icode & 255);
  68. block[bytecount+1] |= ((icode>>8) & 255);
  69. icode = (code>>8) << bitcount;
  70. block[bytecount+2] |= ((icode>>8) & 255);
  71. bitcount += codebits;
  72. while (bitcount >= 8) {       /* locate next starting point */
  73.    bitcount -= 8;
  74.    bytecount++;
  75.    }
  76.  
  77. if (bytecount > 250 || code == endcode) { /* time to write a block */
  78.    if (code == endcode) 
  79.       while (bitcount > 0) {     /* if EOF, find the real end */
  80.          bitcount -= 8;
  81.          bytecount++;
  82.          }
  83.    i = bytecount;
  84.    blockcount = (unsigned char)i;
  85.    fwrite(&blockcount,1,1,out);     /* write the block */
  86.    fwrite(block,i,1,out);
  87.    bytecount = 0;          /* now re-start the block */
  88.    for (j = 0; j < 5; j++)       /* (may have leftover bits) */
  89.       block[j] = block[j+i];
  90.    for (j = 5; j < 266; j++)
  91.       block[j] = 0;
  92.    }
  93. }
  94.  
  95. void inittable(void)          /* routine to init tables */
  96. {
  97. int i;
  98.  
  99. raster(clearcode);         /* signal that table is initialized */
  100.  
  101. numentries = 0;            /* initialize the table */
  102. numrealentries = 0;
  103. nextentry = 1;
  104. lentest = 0;
  105. codebits = startbits;
  106.  
  107. codedstrings[0] = 255;        /* clear the hash entries */
  108. for (i = 0; i < MAXENTRY; i++)
  109.    strlocn[i] = 0;
  110.  
  111. }
  112. void inittable(void);
  113. void savetodisk(char *filename, int xdots, int ydots, int colors)
  114. {
  115. int i, j, ydot, xdot, color, outcolor1, outcolor2;
  116. unsigned int hashentry, Offset = 0, n, Plane = 0;
  117. unsigned char bitsperpixel, x, far *Scr = (unsigned char far *)0xa0000000;
  118.  
  119. if ((out=fopen(filename,"wb")) == NULL) {
  120.    printf(" ?? Couldn't create file %s \n", filename);
  121.    return;
  122.    }
  123.  
  124. bitsperpixel = 0;       /* calculate bits / pixel */
  125. for (i = colors; i >= 2; i /= 2 )
  126.    bitsperpixel++;
  127.  
  128. startbits = bitsperpixel+1;      /* start coding with this many bits */
  129. if (colors == 2)
  130.    startbits++;         /* B&W Klooge */
  131.  
  132. clearcode = 1 << (startbits - 1);   /* set clear and end codes */
  133. endcode = clearcode+1;
  134.  
  135. outcolor1 = 0;          /* use these colors to show progress */
  136. outcolor2 = 1;          /* (this has nothing to do with GIF) */
  137. if (colors > 2) {
  138.    outcolor1 = 2;
  139.    outcolor2 = 3;
  140.    }
  141. if (numsaves && 1 == 0) {     /* reverse the colors on alt saves */
  142.    i = outcolor1;
  143.    outcolor1 = outcolor2;
  144.    outcolor2 = i;
  145.    }
  146.  
  147. fwrite("GIF87a",1,6,out);     /* GIF Signature */
  148.  
  149. fwrite(&xdots,2,1,out);       /* screen descriptor */
  150. fwrite(&ydots,2,1,out);
  151. x = (unsigned char)(128 + ((bitsperpixel-1)<<4) + (bitsperpixel-1));
  152. fwrite(&x,1,1,out);
  153. i = 0;
  154. fwrite(&i,1,1,out);
  155. fwrite(&i,1,1,out);
  156.  
  157. fwrite(GIFColorTable, sizeof(struct _COLOR_GUNS), 256, out);
  158. fwrite(",",1,1,out);       /* Image Descriptor */
  159. i = 0;
  160. fwrite(&i,2,1,out);
  161. fwrite(&i,2,1,out);
  162. fwrite(&xdots,2,1,out);
  163. fwrite(&ydots,2,1,out);
  164. i = 0;
  165. fwrite(&i,1,1,out);
  166.  
  167. bitsperpixel = (unsigned char)(startbits - 1);    /* raster data starts here */
  168. fwrite(&bitsperpixel,1,1,out);
  169.  
  170. codebits = startbits;         /* start encoding */
  171.  
  172. raster(9999);           /* initialize the raster routine */
  173.  
  174. inittable();            /* initialize the LZW tables */
  175.  
  176. SetATIPlane(Plane);
  177. for (ydot = 0; ydot < ydots; ydot++) { /* scan through the dots */
  178.    for (xdot = 0; xdot < xdots; xdot++) {
  179.       while(kbhit()) {
  180.          if(getch() == 27) {
  181.             fclose(out);
  182.             return;
  183.          }
  184.       }
  185.       color = Scr[Offset];
  186.       Scr[Offset++] ^= 0xff;
  187.       if(!Offset)
  188.          SetATIPlane(++Plane);
  189.       teststring[0] = (unsigned char)(++lentest);
  190.       teststring[lentest] = (unsigned char)color;
  191.       if (lentest == 1) {     /* root entry? */
  192.          lastentry = color;
  193.          continue;
  194.          }
  195.       if (lentest == 2)    /* init   the hash code */
  196.          hashcode = 301 * (teststring[1]+1);
  197.       hashcode *= (color + lentest);  /* update the hash code */
  198.       hashentry = ++hashcode % MAXENTRY;
  199.       for( i = 0; i < MAXENTRY; i++) {
  200.          if (++hashentry >= MAXENTRY) hashentry = 0;
  201.          if (memcmp(teststring,
  202.             &codedstrings[strlocn[hashentry]],
  203.             lentest+1) == 0)
  204.                break;
  205.          if (strlocn[hashentry] == 0) i = MAXENTRY;
  206.          }
  207.       /* found an entry and string length isn't too bad */
  208.       if (strlocn[hashentry] != 0 && lentest < MAXTEST-3) {
  209.          lastentry = entrynum[hashentry];
  210.          continue;
  211.          }
  212.       raster(lastentry);         /* write entry */
  213.       numentries++;     /* act like you added one, anyway */
  214.       if (strlocn[hashentry] == 0) {   /* add new string, if any */
  215.          entrynum[hashentry] = numentries+endcode;
  216.          strlocn[hashentry] = nextentry;
  217.          memcpy(&codedstrings[nextentry],
  218.             teststring,lentest+1);
  219.          nextentry += lentest+1;
  220.          numrealentries++;
  221.          }
  222.       teststring[0] = 1;      /* reset current entry */
  223.       teststring[1] = (unsigned char)color;
  224.       lentest = 1;
  225.       lastentry = color;
  226.  
  227.       if ((numentries+endcode) == (1<<codebits))
  228.          codebits++;     /* use longer encoding */
  229.  
  230.       if (numrealentries > (MAXENTRY*2)/3 || /* out of room? */
  231.          nextentry > MAXSTRING-MAXTEST-3) {
  232.          raster(lastentry);      /* flush & restart */
  233.          inittable();
  234.          }
  235.       }
  236.    }
  237. raster(lastentry);         /* tidy up - dump the last code */
  238.  
  239. raster(endcode);        /* finish the map */
  240.  
  241. i = 0;               /* raster data ends here */
  242. fwrite(&i,1,1,out);
  243.  
  244.  
  245. fwrite(";",1,1,out);       /* GIF Terminator */
  246. fclose(out);
  247.    Offset = 0;
  248.    Plane = 0;
  249.    SetATIPlane(Plane);
  250.    for(j = 0; j < ydots; j++) {
  251.       for(i = 0; i < xdots; i++) {
  252.          Scr[Offset++] ^= 0xff;
  253.          if(!Offset)
  254.             SetATIPlane(++Plane);
  255.       }
  256.    }
  257. }
  258.  
  259.  
  260.